package com.dxy.netty.simpledemo;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @Description netty服务器中的处理器（封装到管道）
 * @Author dangxianyue
 * @Date 2023/1/3 18:11
 */
public class SimpleNettyServerHandler extends ChannelInboundHandlerAdapter {

    // 读写数据事件（读取客户端发送的消息）
    // 1. ChannelHandlerContext ctx： 上下文信息，包括管道pipeline，通道channel，地址
    // 2. Object msg： 客户端发送的数据，默认是 Object
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server ctx = " + ctx);

        System.out.println("查看 channel 和 pipeline的关系 ");
        Channel channel = ctx.channel();
        ChannelPipeline channelPipeline = ctx.pipeline(); // 管道是双向链表，出栈入栈


        // 将 msg 转为 ByteBuf 字节缓冲
        // 这个 ByteBuf 是 netty提供的， 不是 nio的ByteBuffer
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发送消息：" + buf.toString(StandardCharsets.UTF_8));
        System.out.println("客户端地址：" + ctx.channel().remoteAddress());

        // 同步任务1
        // 业务场景： 有一个耗时长的业务 -> 异步执行 -> 提交该 channel对应的 NIOEventLoop 的 taskQueue 中；
//        Thread.sleep(10 * 1000);
//        ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端，我是同步任务1\n", StandardCharsets.UTF_8));
//        System.out.println("go on.....");


        // 以上耗时操作的解决方案1：用户程序自定义的普通任务， -》 定时任务提交到 taskQueue 中
        // 注意：任务队列只有一个线程，是一个任务一个任务执行的
        // ctx.channel().eventLoop().execute(线程)
        // 异步任务2
//        ctx.channel().eventLoop().execute(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    Thread.sleep(10 * 1000);
//                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端，我是异步任务2-休眠10s\n", StandardCharsets.UTF_8));
//                } catch (Exception e) {
//                    System.out.println("发生异常, " + e.getMessage());
//                }
//            }
//        });


        // 以上耗时操作的解决方案2：用户自定义延时任务 -》 延时任务提交到 scheduledTaskQueue 中
        // 定时任务3
        ctx.channel().eventLoop().schedule(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端，我是延时任务3-休眠5s\n", StandardCharsets.UTF_8));
                } catch (Exception e) {
                    System.out.println("发生异常, " + e.getMessage());
                }
            }
        }, 5, TimeUnit.SECONDS);
        System.out.println("定时任务 go on.....");

    }

    // 数据读取完毕，回复客户端
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // writeAndFlush 是 write + flush ;把数据写入到缓冲，并刷新
        ChannelFuture channelFuture = ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", StandardCharsets.UTF_8));
        channelFuture.addListener(future -> System.out.println("回复成功"));
    }

    // 处理异常，关闭通道
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
    }
}
